package recursive

import (
	"encoding/json"
	"fmt"
	"reflect"
	"strconv"
	"strings"
)

func travelJsonMap() {
	data := map[string]interface{}{}
	info := make(map[string]interface{})
	// map
	info["name"] = "hello"
	info["phone"] = 123456789
	info["uid"] = 6888640305294214926
	data["info"] = info

	//map
	fuck := make(map[string]interface{})
	fuck["name"] = "hf"
	fuck["phone"] = 755656
	fuck["uid"] = 55555
	data["fuck"] = fuck
	opts := make(map[string]interface{})
	opts["opta"] = 11111
	opts["optb"] = 22222
	fuck["opts"] = opts
	data["fuck"] = fuck
	//数组
	addr := make([]interface{}, 0)
	addr = append(addr, "beijing")
	addr = append(addr, 1234)
	addr = append(addr, 5.3)
	gg := make(map[string]interface{})
	gg["addr"] = addr
	data["gg"] = gg

	//过滤指定位置的元素
	var filter []string
	filter = append(filter, "info.uid", "fuck.opts.opta", "fuck.phone", "gg.addr")

	result := changeAttr(data, filter)
	rb, _ := json.Marshal(result)
	fmt.Printf("result ===> %v\n", string(rb))

}

func changeAttr(data map[string]interface{}, filter []string) map[string]interface{} {

	b, err := json.Marshal(data)
	if err != nil {
		return nil
	}
	m := make(map[string]interface{})
	decoder := json.NewDecoder(strings.NewReader(string(b)))
	decoder.UseNumber()
	err = decoder.Decode(&m)
	if err != nil {
		return nil
	}

	var change func(map[string]interface{}, string) map[string]interface{}
	var changeI func(k string, v interface{}, prefix string) interface{}

	change = func(m map[string]interface{}, prefix string) map[string]interface{} {
		result := map[string]interface{}{}
		for k, v := range m {
			val := changeI(k, v, prefix)
			result[k] = val
		}
		return result
	}

	changeI = func(k string, v interface{}, prefix string) interface{} {
		switch m := v.(type) {
		case map[string]interface{}: //map
			prefix := strings.Join([]string{prefix, k, "."}, "")
			return change(m, prefix)
		case []interface{}: //数组型
			res := make([]interface{}, len(m))
			for i, v := range m {
				res[i] = changeI(k, v, prefix)
			}
			return res
		default:
			rv := reflect.ValueOf(v)
			if rv.Kind() == reflect.Slice || rv.Kind() == reflect.Array {
				res := make([]interface{}, rv.Len())
				for i := range res {
					res[i] = changeI(k, rv.Index(i).Interface(), prefix)
				}
				return res
			}
			key := strings.Join([]string{prefix, k}, "")
			if IsContain(filter, key) {
				if rv.Kind() == reflect.String && rv.Type().String() == "json.Number" {
					return rv.String()
				}
				if rv.Kind() == reflect.Int {
					return strconv.FormatInt(int64(v.(int)), 10)
				}
				if rv.Kind() == reflect.Int8 {
					return strconv.FormatInt(int64(v.(int8)), 10)
				}
				if rv.Kind() == reflect.Int32 {
					return strconv.FormatInt(int64(v.(int32)), 10)
				}
				if rv.Kind() == reflect.Float32 {
					return strconv.FormatFloat(float64(v.(float32)), 'f', -1, 64)
				}
				if rv.Kind() == reflect.Float64 {
					return strconv.FormatFloat(v.(float64), 'f', -1, 64)
				}
			}
			return v
		}
	}

	result := change(m, "")
	return result
}

func IsContain(items []string, item string) bool {
	for _, eachItem := range items {
		if eachItem == item {
			return true
		}
	}
	return false
}
